#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
主窗口模块，提供用户界面和程序入口。
"""

import os
import sys
import time
import numpy as np
import cv2

# 修复导入问题
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QListWidget, QFileDialog, QLabel, QMenu, QAction,
    QMessageBox, QInputDialog, QStatusBar, QSplitter, QToolBar, QDialog
)
from PyQt5.QtCore import Qt, QSettings, QSize
from PyQt5.QtGui import QIcon

# 修改导入路径，避免使用src前缀
try:
    # 尝试直接导入（从项目根目录运行时）
    from src.ui.image_canvas import ImageCanvas
    from src.ui.region_settings_dialog import RegionSettingsDialog
    from src.ui.save_options_dialog import SaveOptionsDialog  
    from src.ui.background_removal_dialog import BackgroundRemovalDialog
    from src.core.image_processor import ImageProcessor
    from src.core.region_manager import RegionManager
    from src.utils.file_utils import ensure_dir, get_safe_filename, get_file_extension
except ImportError:
    # 如果失败，尝试使用相对导入（从src目录运行时）
    from ui.image_canvas import ImageCanvas
    from ui.region_settings_dialog import RegionSettingsDialog
    from ui.save_options_dialog import SaveOptionsDialog
    from ui.background_removal_dialog import BackgroundRemovalDialog
    from core.image_processor import ImageProcessor
    from core.region_manager import RegionManager
    from utils.file_utils import ensure_dir, get_safe_filename, get_file_extension


class ImageCutterApp(QMainWindow):
    """图片剪切工具主窗口类"""
    
    def __init__(self):
        """初始化主窗口"""
        super().__init__()
        
        # 创建核心组件
        self.processor = ImageProcessor()
        self.region_mgr = RegionManager()
        
        # 图像数据
        self.original_image = None
        self.image_paths = []
        self.current_image_index = 0
        
        # 配置文件
        self.settings = QSettings("image_cutter", "config")
        
        # 历史记录
        self.recent_files = self.settings.value("recent_files", [], str)
        self.last_directory = self.settings.value("last_directory", "", str)
        
        # 对话框状态
        self.dialog_active = False  # 是否有对话框正在显示
        
        # 初始化界面
        self.init_ui()
        
        # 加载上次打开的图片
        self.load_last_image()
    
    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口属性
        self.setWindowTitle("图片剪切工具")
        self.setMinimumSize(800, 600)
        
        # 创建状态栏
        self.setStatusBar(QStatusBar())
        self.statusBar().showMessage("就绪")
        
        # 创建主界面组件
        self.canvas = ImageCanvas(self)
        self.setCentralWidget(self.canvas)
        
        # 连接信号
        self.canvas.region_selected.connect(self.on_region_selected)
        self.canvas.region_right_clicked.connect(self.on_region_right_clicked)
        self.canvas.background_right_clicked.connect(self.on_background_right_clicked)
        self.canvas.region_adjusted.connect(self.on_region_adjusted)
        self.canvas.region_double_clicked.connect(self.on_region_double_clicked)
        
        # 创建菜单栏
        self.create_menus()
        
        # 创建工具栏
        self.create_toolbars()
        
        # 显示窗口
        self.show()
    
    def create_menus(self):
        """创建菜单栏"""
        # 文件菜单
        file_menu = self.menuBar().addMenu("文件")
        
        open_action = QAction("打开图片", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_image)
        file_menu.addAction(open_action)
        
        open_multi_action = QAction("打开多张图片", self)
        open_multi_action.triggered.connect(self.open_multiple_images)
        file_menu.addAction(open_multi_action)
        
        # 添加最近打开的文件菜单
        self.recent_menu = file_menu.addMenu("最近打开")
        self.update_recent_menu()
        
        file_menu.addSeparator()
        
        save_action = QAction("保存当前区域", self)
        save_action.setShortcut("Ctrl+S")
        save_action.triggered.connect(self.save_current_region)
        file_menu.addAction(save_action)
        
        save_all_action = QAction("保存所有区域", self)
        save_all_action.setShortcut("Ctrl+Shift+S")
        save_all_action.triggered.connect(self.save_all_regions)
        file_menu.addAction(save_all_action)
        
        file_menu.addSeparator()
        
        exit_action = QAction("退出", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)
        
        # 编辑菜单
        edit_menu = self.menuBar().addMenu("编辑")
        
        clear_action = QAction("清除所有区域", self)
        clear_action.triggered.connect(self.clear_all_regions)
        edit_menu.addAction(clear_action)
        
        # 视图菜单
        view_menu = self.menuBar().addMenu("视图")
        
        next_image_action = QAction("下一张图片", self)
        next_image_action.setShortcut("PgDown")
        next_image_action.triggered.connect(self.next_image)
        view_menu.addAction(next_image_action)
        
        prev_image_action = QAction("上一张图片", self)
        prev_image_action.setShortcut("PgUp")
        prev_image_action.triggered.connect(self.prev_image)
        view_menu.addAction(prev_image_action)
    
    def create_toolbars(self):
        """创建工具栏"""
        # 主工具栏
        main_toolbar = QToolBar("主工具栏", self)
        self.addToolBar(main_toolbar)
        
        # 添加工具栏按钮
        open_action = QAction("打开", self)
        open_action.triggered.connect(self.open_image)
        main_toolbar.addAction(open_action)
        
        save_all_action = QAction("保存所有", self)
        save_all_action.triggered.connect(self.save_all_regions)
        main_toolbar.addAction(save_all_action)
        
        clear_action = QAction("清除区域", self)
        clear_action.triggered.connect(self.clear_all_regions)
        main_toolbar.addAction(clear_action)
    
    def update_recent_menu(self):
        """更新最近打开的文件菜单"""
        self.recent_menu.clear()
        for file_path in self.recent_files:
            if os.path.exists(file_path):
                action = QAction(os.path.basename(file_path), self)
                action.setData(file_path)
                action.triggered.connect(lambda checked, path=file_path: self.open_image(path))
                self.recent_menu.addAction(action)
    
    def add_to_recent_files(self, file_path):
        """添加文件到最近打开列表
        
        参数:
            file_path (str): 文件路径
        """
        if file_path in self.recent_files:
            self.recent_files.remove(file_path)
        self.recent_files.insert(0, file_path)
        
        # 限制最近文件数量为10个
        self.recent_files = self.recent_files[:10]
        
        # 保存到配置文件
        self.settings.setValue("recent_files", self.recent_files)
        self.settings.setValue("last_directory", os.path.dirname(file_path))
        
        # 更新菜单
        self.update_recent_menu()
    
    def load_last_image(self):
        """加载上次打开的图片"""
        if self.recent_files:
            last_file = self.recent_files[0]
            if os.path.exists(last_file):
                self.open_image(last_file)
    
    def open_image(self, file_path=None):
        """打开图片文件"""
        try:
            # 如果没有提供文件路径，显示文件选择对话框
            if file_path is None or not file_path:
                initial_dir = self.last_directory if self.last_directory else ""
                file_path, _ = QFileDialog.getOpenFileName(
                    self, 
                    "打开图片", 
                    initial_dir, 
                    "图片文件 (*.png *.jpg *.bmp *.jpeg);;所有文件 (*.*)"
                )
                
            # 检查用户是否选择了文件
            if not file_path:
                return
                
            # 显示加载状态
            self.statusBar().showMessage(f"正在加载图片: {file_path}")
            QApplication.processEvents()
            
            # 加载图像
            self.original_image = self.processor.load_image(file_path)
            
            # 检查图像是否加载成功
            if self.original_image is None:
                QMessageBox.critical(self, "错误", f"无法加载图片: {file_path}")
                self.statusBar().showMessage("加载图片失败")
                return
                
            # 更新图像路径
            if file_path not in self.image_paths:
                self.image_paths.append(file_path)
            self.current_image_index = self.image_paths.index(file_path)
                
            # 设置图像到画布
            self.canvas.set_image(self.original_image)
            
            # 更新区域管理器中的当前图片名称
            self.region_mgr.set_current_image(file_path)
            
            # 添加到最近打开的文件
            self.add_to_recent_files(file_path)
            
            # 更新状态信息
            self.statusBar().showMessage(f"已加载图片: {os.path.basename(file_path)}")
            
            # 清除现有区域
            self.canvas.clear_regions()
            self.region_mgr.regions = []
            
            # 刷新显示
            self.canvas.update()
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"加载图片时出错: {str(e)}")
            self.statusBar().showMessage("加载图片失败")
            import traceback
            traceback.print_exc()
    
    def open_multiple_images(self):
        """打开多张图片"""
        try:
            file_paths, _ = QFileDialog.getOpenFileNames(
                self, "打开多张图片", "", "图片文件 (*.png *.jpg *.bmp *.jpeg)"
            )
            
            if file_paths:
                self.image_paths = file_paths
                self.current_image_index = 0
                
                # 加载第一张图片
                self.open_image(file_paths[0])
                
                self.statusBar().showMessage(f"已加载 {len(file_paths)} 张图片。当前第 1/{len(file_paths)}")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"打开多张图片时出错: {str(e)}")
            import traceback
            traceback.print_exc()
    
    def next_image(self):
        """显示下一张图片"""
        if not self.image_paths or len(self.image_paths) <= 1:
            self.statusBar().showMessage("没有更多图片可显示")
            return
            
        next_index = (self.current_image_index + 1) % len(self.image_paths)
        self.current_image_index = next_index
        
        # 加载图片，但不通过open_image方法，避免覆盖image_paths
        try:
            file_path = self.image_paths[next_index]
            
            # 显示加载状态
            self.statusBar().showMessage(f"正在加载图片: {file_path}")
            QApplication.processEvents()
            
            # 加载图像
            self.original_image = self.processor.load_image(file_path)
            
            # 检查图像是否加载成功
            if self.original_image is None:
                QMessageBox.critical(self, "错误", f"无法加载图片: {file_path}")
                self.statusBar().showMessage("加载图片失败")
                return
                
            # 设置图像到画布
            self.canvas.set_image(self.original_image)
            
            # 更新区域管理器中的当前图片名称
            self.region_mgr.set_current_image(file_path)
            
            # 更新状态
            self.statusBar().showMessage(f"当前第 {next_index+1}/{len(self.image_paths)} - {file_path}")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"加载图片时出错: {str(e)}")
            self.statusBar().showMessage("加载图片时出错")
    
    def prev_image(self):
        """显示上一张图片"""
        if not self.image_paths or len(self.image_paths) <= 1:
            self.statusBar().showMessage("没有更多图片可显示")
            return
            
        prev_index = (self.current_image_index - 1) % len(self.image_paths)
        self.current_image_index = prev_index
        
        # 加载图片，但不通过open_image方法，避免覆盖image_paths
        try:
            file_path = self.image_paths[prev_index]
            
            # 显示加载状态
            self.statusBar().showMessage(f"正在加载图片: {file_path}")
            QApplication.processEvents()
            
            # 加载图像
            self.original_image = self.processor.load_image(file_path)
            
            # 检查图像是否加载成功
            if self.original_image is None:
                QMessageBox.critical(self, "错误", f"无法加载图片: {file_path}")
                self.statusBar().showMessage("加载图片失败")
                return
                
            # 设置图像到画布
            self.canvas.set_image(self.original_image)
            
            # 更新区域管理器中的当前图片名称
            self.region_mgr.set_current_image(file_path)
            
            # 更新状态
            self.statusBar().showMessage(f"当前第 {prev_index+1}/{len(self.image_paths)} - {file_path}")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"加载图片时出错: {str(e)}")
            self.statusBar().showMessage("加载图片时出错")
    
    def on_region_selected(self, rect):
        """区域选择事件处理
        
        参数:
            rect (tuple): 选择的区域 (x, y, w, h)
        """
        if not rect or rect[2] < 10 or rect[3] < 10 or self.original_image is None:
            return
            
        # 设置对话框活动标志
        self.dialog_active = True
        self.canvas.pause_suggestion = True
            
        # 解析区域数据，确保是整数
        x, y, w, h = map(int, rect)
        print(f"选中区域: ({x},{y},{w},{h})")
        
        # 创建整数坐标的矩形
        int_rect = (x, y, w, h)
        
        # 创建区域设置对话框
        dialog = RegionSettingsDialog(int_rect, self)
        result = dialog.exec_()
        
        # 处理对话框结果
        if result == RegionSettingsDialog.Accepted:
            settings = dialog.get_settings()
            if settings:
                # 更新区域数据
                x = settings["x"]
                y = settings["y"]
                w = settings["width"]
                h = settings["height"]
                name = self.region_mgr.format_region_name(x, y, w, h)
                print(f"创建区域: ({x},{y},{w},{h}), 名称={name}")
                
                # 添加到区域管理器
                index = self.region_mgr.add_region(x, y, w, h, name)
                print(f"添加区域成功: 索引={index}")
                
                # 设置背景滤除参数
                enable_bg_removal = settings["enable_bg_removal"]
                bg_removal = {
                    "enable": enable_bg_removal,
                    "color": settings["bg_color"],
                    "threshold": settings["bg_threshold"]
                }
                
                # 如果启用了背景滤除且尚未完成背景滤除设置，显示背景滤除设置对话框
                # dialog.bg_removal_initialized属性表示是否已经完成背景滤除设置
                if enable_bg_removal and not hasattr(dialog, 'bg_removal_initialized') or not dialog.bg_removal_initialized:
                    # 获取区域图像
                    region_img = self.original_image[y:y+h, x:x+w].copy()
                    
                    # 创建背景滤除对话框 - 传递正确格式的参数
                    bg_dialog = BackgroundRemovalDialog(region_img, self, (bg_removal["color"], bg_removal["threshold"]))
                    
                    if bg_dialog.exec_() == QDialog.Accepted:
                        # 获取背景滤除设置
                        bg_settings = bg_dialog.get_settings()
                        
                        # 更新背景滤除参数
                        bg_removal["color"] = bg_settings[0]  # 返回值是元组，第一个元素是颜色列表
                        bg_removal["threshold"] = bg_settings[1]  # 第二个元素是阈值
                
                # 将背景滤除参数保存到区域属性中
                self.region_mgr.set_region_property(index, "bg_removal", bg_removal)
                
                # 更新当前选中的区域
                self.region_mgr.current_index = index
                
                # 调试区域管理器中的区域数据
                regions = self.region_mgr.regions
                print(f"区域管理器中的区域: {regions}")
                print(f"区域数量: {self.region_mgr.get_region_count()}")
                
                # 直接设置画布的regions属性和current_index属性
                self.canvas.regions = regions[:]  # 使用切片创建副本
                self.canvas.current_index = index
                print(f"画布中的区域: {self.canvas.regions}")
                
                # 清除临时显示的矩形
                self.canvas.clear_suggested_region()
                self.canvas.current_rect = None
                
                # 使用手动绘制方法
                self.canvas.manual_draw_regions()
                
                self.statusBar().showMessage(f"已添加区域 {index+1}")
        
        # 恢复对话框活动标志
        self.dialog_active = False
        self.canvas.pause_suggestion = False
    
    def on_region_right_clicked(self, region_index, global_pos):
        """区域右键点击事件处理
        
        参数:
            region_index (int): 区域索引
            global_pos (QPoint): 全局鼠标位置
        """
        if not self.region_mgr.get_region(region_index):
            return
            
        # 创建上下文菜单
        context_menu = QMenu(self)
        
        edit_action = context_menu.addAction("编辑区域")
        save_action = context_menu.addAction("保存此区域")
        process_action = context_menu.addAction("背景滤除")
        remove_action = context_menu.addAction("删除此区域")
        
        # 显示菜单
        action = context_menu.exec_(global_pos)
        
        if action == edit_action:
            self.edit_region(region_index)
        elif action == save_action:
            self.save_region(region_index)
        elif action == process_action:
            self.process_region(region_index)
        elif action == remove_action:
            self.remove_region(region_index)
    
    def on_background_right_clicked(self, x, y, global_pos):
        """背景右键点击事件处理
        
        参数:
            x (int): 图像X坐标
            y (int): 图像Y坐标
            global_pos (QPoint): 全局鼠标位置
        """
        # 创建上下文菜单
        context_menu = QMenu(self)
        
        detect_action = context_menu.addAction("智能检测区域")
        
        # 如果已经存在建议剪切区域，添加直接选择选项
        if self.canvas.current_rect:
            rect = self.canvas.current_rect
            
            # 添加带有区域信息的菜单项
            rect_info = f"选择当前区域 ({rect[2]}x{rect[3]})"
            select_action = context_menu.addAction(rect_info)
            
            # 添加分隔线
            context_menu.addSeparator()
        else:
            select_action = None
        
        # 显示菜单
        action = context_menu.exec_(global_pos)
        
        if action == detect_action:
            self.detect_area_at_point(x, y)
        elif action == select_action and self.canvas.current_rect:
            # 用户选择了当前建议的区域
            self.select_suggested_region()
    
    def detect_area_at_point(self, x, y):
        """在指定位置检测区域
        
        参数:
            x (int): 图像X坐标
            y (int): 图像Y坐标
        """
        if self.original_image is None:
            return
            
        # 检测区域
        rect = self.processor.detect_area(self.original_image, x, y, self.canvas.sensitivity)
        
        if rect:
            # 更新画布中的当前矩形，但不立即添加到区域管理器
            self.canvas.current_rect = rect
            self.canvas.update_display()
            
            # 弹出区域设置对话框
            self.on_region_selected(rect)
        else:
            self.statusBar().showMessage("未检测到区域，请尝试调整敏感度或选择其他位置")
    
    def edit_region(self, region_index):
        """编辑区域设置
        
        参数:
            region_index (int): 区域索引
        """
        # 判断区域索引是否有效
        if region_index < 0 or region_index >= len(self.region_mgr.regions):
            return
            
        # 获取当前区域数据
        region_data = self.region_mgr.regions[region_index]
        
        # 确保坐标是整数
        if len(region_data) >= 4:
            x, y, w, h = region_data[:4]
            int_region = (int(x), int(y), int(w), int(h))
            if len(region_data) > 4:
                int_region = int_region + (region_data[4],)
        else:
            return
        
        # 创建区域设置对话框
        dialog = RegionSettingsDialog(int_region, self)
        result = dialog.exec_()
        
        # 处理对话框结果
        if result == RegionSettingsDialog.Accepted:
            settings = dialog.get_settings()
            if settings:
                # 更新区域数据
                x = settings["x"]
                y = settings["y"]
                w = settings["width"]
                h = settings["height"]
                
                # 使用用户输入的区域名称
                name = settings["name"]
                if not name:  # 如果用户未输入名称，则使用默认格式
                    name = self.region_mgr.format_region_name(x, y, w, h)
                
                # 更新区域管理器
                self.region_mgr.regions[region_index] = (x, y, w, h, name)
                
                # 更新画布
                self.canvas.update_region(region_index, (x, y, w, h, name))
                
                # 获取背景滤除设置
                enable_bg_removal = settings["enable_bg_removal"]
                bg_removal = {
                    "enable": enable_bg_removal,
                    "color": settings["bg_color"],
                    "threshold": settings["bg_threshold"]
                }
                
                # 如果启用了背景滤除且尚未完成背景滤除设置，显示背景滤除设置对话框
                # dialog.bg_removal_initialized属性表示是否已经完成背景滤除设置
                if enable_bg_removal and not hasattr(dialog, 'bg_removal_initialized') or not dialog.bg_removal_initialized:
                    # 获取区域图像
                    region_img = self.original_image[y:y+h, x:x+w].copy()
                    
                    # 创建背景滤除对话框
                    bg_dialog = BackgroundRemovalDialog(region_img, self, (bg_removal["color"], bg_removal["threshold"]))
                    
                    if bg_dialog.exec_() == QDialog.Accepted:
                        # 获取背景滤除设置
                        bg_settings = bg_dialog.get_settings()
                        
                        # 更新背景滤除参数
                        bg_removal["color"] = bg_settings[0]  # 返回值是元组，第一个元素是颜色列表
                        bg_removal["threshold"] = bg_settings[1]  # 第二个元素是阈值
                
                # 将背景滤除参数保存到区域属性中
                self.region_mgr.set_region_property(region_index, "bg_removal", bg_removal)
                
                # 更新状态栏
                self.statusBar().showMessage(f"区域 {region_index+1} 设置已更新")
    
    def remove_region(self, region_index):
        """删除区域
        
        参数:
            region_index (int): 区域索引
        """
        region = self.region_mgr.get_region(region_index)
        if not region:
            return
            
        # 删除区域
        self.region_mgr.remove_region(region_index)
        
        # 更新画布
        self.canvas.draw_regions(self.region_mgr.get_all_regions(), self.region_mgr.current_index)
        
        self.statusBar().showMessage(f"已删除区域")
    
    def save_region(self, region_index):
        """保存单个区域
        
        参数:
            region_index (int): 区域索引
        """
        print(f"开始保存区域: 索引={region_index}")
        region = self.region_mgr.get_region(region_index)
        if not region or self.original_image is None:
            print(f"保存失败: region={region is not None}, original_image={self.original_image is not None}")
            QMessageBox.warning(self, "提示", "请先选择区域并加载图像")
            return
            
        try:
            # 获取区域信息
            x, y, w, h, name = region[:5]
            print(f"区域信息: 位置=({x},{y}), 大小=({w},{h}), 名称={name}")
            
            # 处理文件名，移除非法字符
            safe_name = self.sanitize_filename(name)
            print(f"处理后的安全文件名: {safe_name}")
            
            # 剪切图像
            print(f"正在剪切图像区域: ({x},{y},{w},{h})")
            print(f"原始图像形状: {self.original_image.shape}")
            
            # 检查坐标是否在有效范围内
            if (x < 0 or y < 0 or 
                x + w > self.original_image.shape[1] or 
                y + h > self.original_image.shape[0]):
                print(f"警告: 区域坐标超出图像范围! 图像大小={self.original_image.shape}")
                QMessageBox.warning(self, "警告", "区域坐标超出图像范围，可能会导致剪切结果异常")
                
            cut_img = self.original_image[y:y+h, x:x+w]
            print(f"剪切后图像形状: {cut_img.shape}")
            
            # 获取用户的文档目录作为默认目录
            import os
            default_dir = os.path.expanduser("~/Pictures")
            if not os.path.exists(default_dir):
                default_dir = os.path.expanduser("~/Documents")
            if not os.path.exists(default_dir):
                default_dir = os.path.expanduser("~")
                
            default_path = os.path.join(default_dir, safe_name)
            
            # 弹出保存对话框
            print(f"显示保存对话框，默认路径: {default_path}")
            file_path, filter_type = QFileDialog.getSaveFileName(
                self, "保存区域", default_path, "PNG (*.png);;JPEG (*.jpg);;BMP (*.bmp)"
            )
            
            if not file_path:
                print("用户取消了保存操作")
                return
                
            print(f"用户选择的保存路径: {file_path}")
            print(f"选择的过滤器: {filter_type}")
                
            # 确定格式
            format_type = "PNG"
            if file_path.lower().endswith(".jpg") or file_path.lower().endswith(".jpeg"):
                format_type = "JPEG"
            elif file_path.lower().endswith(".bmp"):
                format_type = "BMP"
            
            print(f"确定的格式类型: {format_type}")
            
            # 检查路径是否存在
            save_dir = os.path.dirname(file_path)
            if save_dir and not os.path.exists(save_dir):
                print(f"保存目录不存在，尝试创建: {save_dir}")
                try:
                    os.makedirs(save_dir, exist_ok=True)
                    print(f"成功创建目录: {save_dir}")
                except Exception as e:
                    print(f"创建目录失败: {str(e)}")
                    QMessageBox.critical(self, "错误", f"无法创建保存目录: {save_dir}\n{str(e)}")
                    return
            
            # 检查文件是否可写
            try:
                # 尝试判断是否有写入权限
                if os.path.exists(file_path):
                    try:
                        with open(file_path, 'ab') as f:
                            pass
                        print("文件存在且可写")
                    except PermissionError:
                        print("文件存在但无法写入")
                        alt_path = os.path.join(os.path.expanduser("~"), os.path.basename(file_path))
                        result = QMessageBox.question(
                            self, 
                            "权限错误", 
                            f"无法写入文件 {file_path}，是否保存到 {alt_path}？", 
                            QMessageBox.Yes | QMessageBox.No, 
                            QMessageBox.Yes
                        )
                        if result == QMessageBox.Yes:
                            file_path = alt_path
                            print(f"改用替代路径: {file_path}")
                        else:
                            print("用户取消保存")
                            return
            except Exception as e:
                print(f"检查文件权限时出错: {str(e)}")
            
            # 保存图像
            print(f"正在调用保存图像函数: file_path={file_path}, format={format_type}")
            success = self.processor.save_image(cut_img, file_path, format_type)
            
            if success:
                print(f"保存成功: {file_path}")
                self.statusBar().showMessage(f"已保存区域: {file_path}")
                
                # 显示保存成功对话框
                QMessageBox.information(self, "成功", f"区域已成功保存到:\n{file_path}")
            else:
                print(f"保存失败: {file_path}")
                error_msg = f"保存区域失败: {file_path}\n\n可能的原因:\n- 没有写入权限\n- 文件被其他程序占用\n- 路径包含非法字符（如 : * ? \" < > | 等）\n\n建议操作:\n- 尝试保存到桌面或者文档目录\n- 使用简短的文件名\n- 检查文件是否已被其他程序打开\n- 右键区域选择『编辑区域』修改名称"
                QMessageBox.warning(self, "警告", error_msg)
        except Exception as e:
            print(f"保存区域时发生异常: {str(e)}")
            
            # 获取更多异常信息
            import sys
            exc_type, exc_obj, exc_tb = sys.exc_info()
            import traceback
            tb_details = traceback.extract_tb(exc_tb)
            print(f"异常类型: {exc_type}")
            print(f"异常位置: 文件={tb_details[-1].filename}, 行={tb_details[-1].lineno}")
            
            error_msg = f"保存区域时出错: {str(e)}\n\n请尝试以下方法:\n- 使用不含特殊字符的文件名\n- 保存到其他文件夹\n- 确保有足够的磁盘空间"
            QMessageBox.critical(self, "错误", error_msg)
            traceback.print_exc()
    
    def sanitize_filename(self, filename):
        """处理文件名，移除非法字符
        
        参数:
            filename (str): 原始文件名
            
        返回:
            str: 处理后的安全文件名
        """
        print(f"开始处理文件名: '{filename}'")
        
        if not filename:
            print("文件名为空，使用默认名称 'region'")
            return "region"
            
        # Windows文件系统不允许的字符
        invalid_chars = '<>:"/\\|?*'
        print(f"Windows文件系统不允许的字符: '{invalid_chars}'")
        
        # 检查文件名中是否含有非法字符
        has_invalid = False
        for c in filename:
            if c in invalid_chars:
                has_invalid = True
                print(f"发现非法字符: '{c}'")
        
        if has_invalid:
            print("文件名中包含非法字符，需要替换")
                
        # 处理非法字符
        safe_name = ""
        for c in filename:
            if c in invalid_chars:
                # 将非法字符替换为下划线
                safe_name += "_"
                print(f"字符 '{c}' 替换为 '_'")
            else:
                safe_name += c
        
        print(f"替换非法字符后: '{safe_name}'")
                
        # 移除文件名开头和结尾的空格和句点
        old_name = safe_name
        safe_name = safe_name.strip(". ")
        if old_name != safe_name:
            print(f"移除首尾空格和句点: '{old_name}' -> '{safe_name}'")
                
        # 如果文件名为空，使用默认名称
        if not safe_name:
            safe_name = "region"
            print("处理后文件名为空，使用默认名称 'region'")
            
        # 移除多余的下划线
        if "__" in safe_name:
            old_name = safe_name
            while "__" in safe_name:
                safe_name = safe_name.replace("__", "_")
            print(f"移除多余下划线: '{old_name}' -> '{safe_name}'")
            
        # 限制文件名长度，避免路径过长问题
        if len(safe_name) > 100:
            old_name = safe_name
            safe_name = safe_name[:100]
            print(f"文件名过长，截断至100字符: '{old_name}' -> '{safe_name}'")
            
        print(f"最终处理结果: '{filename}' -> '{safe_name}'")
        return safe_name
    
    def save_current_region(self):
        """保存当前选中的区域"""
        current_index = self.region_mgr.current_index
        if current_index >= 0:
            self.save_region(current_index)
        else:
            QMessageBox.information(self, "提示", "请先选择一个区域")
    
    def save_all_regions(self):
        """保存所有区域"""
        print("开始批量保存所有区域")
        if self.original_image is None:
            print("错误: 原始图像未加载")
            QMessageBox.warning(self, "警告", "请先加载原始图像")
            return
            
        # 获取区域数量
        region_count = self.region_mgr.get_region_count()
        print(f"区域总数: {region_count}")
        if region_count == 0:
            print("错误: 没有设置任何区域")
            QMessageBox.warning(self, "警告", "没有设置任何区域")
            return
            
        # 弹出保存选项对话框
        print("显示保存选项对话框")
        from src.ui.save_options_dialog import SaveOptionsDialog
        options_dialog = SaveOptionsDialog(self)
        if options_dialog.exec_() != QDialog.Accepted:
            print("用户取消了保存选项设置")
            return
            
        # 获取用户设置的选项
        options = options_dialog.get_options()
        print(f"保存选项: {options}")
        
        # 选择保存目录
        print("显示目录选择对话框")
        save_dir = QFileDialog.getExistingDirectory(
            self,
            "选择保存目录",
            os.getcwd(),
            QFileDialog.ShowDirsOnly
        )
        
        if not save_dir:
            print("用户取消了目录选择")
            return
            
        print(f"选择的保存目录: {save_dir}")
        
        # 检查目录是否存在和是否可写
        if not os.path.exists(save_dir):
            print(f"目录不存在，尝试创建: {save_dir}")
            try:
                os.makedirs(save_dir, exist_ok=True)
            except Exception as e:
                print(f"创建目录失败: {str(e)}")
                QMessageBox.critical(self, "错误", f"无法创建目录: {save_dir}\n{str(e)}")
                return
                
        # 检查目录权限
        try:
            import tempfile
            with tempfile.NamedTemporaryFile(dir=save_dir, delete=True) as temp:
                print(f"目录权限检查通过: {save_dir}")
        except Exception as e:
            print(f"目录权限检查失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"无法写入目录: {save_dir}\n{str(e)}")
            return
            
        # 处理所有区域
        success_count = 0
        try:
            print(f"开始处理 {region_count} 个区域")
            # 遍历所有区域
            for i in range(region_count):
                print(f"处理区域 {i+1}/{region_count}")
                # 获取区域数据
                region = self.region_mgr.get_region(i)
                if not region:
                    print(f"区域 {i} 数据不存在，跳过")
                    continue
                    
                # 解析区域数据
                if len(region) >= 5:
                    x, y, w, h, name = region[:5]
                    print(f"区域 {i+1} 信息: 位置=({x},{y}), 大小=({w},{h}), 名称={name}")
                else:
                    print(f"区域 {i} 数据不完整: {region}，跳过")
                    continue
                
                # 处理文件名，移除非法字符
                safe_name = self.sanitize_filename(name)
                print(f"处理后的安全文件名: {safe_name}")
                
                # 生成保存文件名
                filename = safe_name
                if options["include_coordinates"]:
                    # 添加下划线和字母区分各个坐标值，避免产生歧义
                    filename += f"_x{x}_y{y}_w{w}_h{h}"
                filename += f".{options['format'].lower()}"
                print(f"生成的文件名: {filename}")
                
                # 完整保存路径
                full_path = os.path.join(save_dir, filename)
                print(f"完整保存路径: {full_path}")
                
                # 剪切图像
                print(f"正在剪切图像区域: ({x},{y},{w},{h})")
                
                # 检查坐标是否在有效范围内
                if (x < 0 or y < 0 or 
                    x + w > self.original_image.shape[1] or 
                    y + h > self.original_image.shape[0]):
                    print(f"警告: 区域坐标超出图像范围! 图像大小={self.original_image.shape}")
                
                cut_img = self.original_image[y:y+h, x:x+w].copy()
                print(f"剪切后图像形状: {cut_img.shape}")
                
                # 处理PNG背景透明
                if options["remove_background"] and options["format"] == "PNG":
                    print("需要进行背景滤除处理")
                    # 获取区域属性中的背景滤除设置
                    bg_props = self.region_mgr.get_region_property(i, "bg_removal", {})
                    bg_color = bg_props.get("color", [0, 255, 0])  # 默认绿色
                    target_color = bg_props.get("target_color", None)  # 获取图像左上角颜色
                    # 确保bg_threshold是整数
                    bg_threshold = int(bg_props.get("threshold", 0))
                    print(f"背景滤除属性: color={bg_color}, target={target_color}, threshold={bg_threshold}")
                    
                    # 如果没有指定目标颜色，使用图像左上角第一个像素点的颜色
                    if target_color is None and cut_img.size > 0:
                        target_color = [int(c) for c in cut_img[0, 0]]
                        print(f"从图像左上角获取目标颜色: {target_color}")
                    elif target_color is None:
                        target_color = [255, 255, 255]  # 默认白色
                        print(f"使用默认目标颜色(白色): {target_color}")
                    
                    # 弹出背景色设置对话框，传递正确格式的背景滤除参数
                    print("显示背景滤除设置对话框")
                    bg_dialog = BackgroundRemovalDialog(cut_img, self, (bg_color, target_color, bg_threshold))
                    
                    if bg_dialog.exec_():
                        print("用户确认了背景滤除设置")
                        bg_settings = bg_dialog.get_settings()
                        print(f"背景滤除设置: {bg_settings}")
                        
                        # 移除背景色 - bg_settings是元组(颜色列表, 目标颜色列表, 阈值)
                        print("开始进行背景滤除处理")
                        rgba_img = self.processor.remove_background(
                            cut_img, 
                            bg_settings[1],  # 目标颜色
                            bg_settings[2]   # 阈值
                        )
                        print(f"背景滤除后图像形状: {rgba_img.shape}")
                        
                        # 保存图像
                        print(f"保存RGBA图像: {full_path}")
                        success = self.processor.save_image(rgba_img, full_path, options["format"])
                    else:
                        print("用户取消了背景滤除设置，使用普通保存")
                        # 用户取消了背景设置，使用普通保存
                        success = self.processor.save_image(cut_img, full_path, options["format"])
                else:
                    # 直接保存图像
                    print(f"直接保存图像: {full_path}, 格式={options['format']}")
                    success = self.processor.save_image(cut_img, full_path, options["format"])
                
                if success:
                    print(f"区域 {i+1} 保存成功")
                    success_count += 1
                else:
                    print(f"区域 {i+1} 保存失败")
                
            # 显示结果
            print(f"保存完成: 成功={success_count}, 总数={region_count}")
            if success_count > 0:
                QMessageBox.information(
                    self, 
                    "成功", 
                    f"已成功保存 {success_count}/{region_count} 个区域到 {save_dir}"
                )
            else:
                QMessageBox.warning(self, "警告", "没有成功保存任何区域")
            
        except Exception as e:
            print(f"保存区域时发生异常: {str(e)}")
            
            # 获取更多异常信息
            import sys
            exc_type, exc_obj, exc_tb = sys.exc_info()
            import traceback
            tb_details = traceback.extract_tb(exc_tb)
            print(f"异常类型: {exc_type}")
            print(f"异常位置: 文件={tb_details[-1].filename}, 行={tb_details[-1].lineno}")
            
            QMessageBox.critical(self, "错误", f"保存区域时出错: {str(e)}")
            traceback.print_exc()
    
    def clear_all_regions(self):
        """清除所有区域"""
        if not self.region_mgr.get_region_count():
            return
            
        reply = QMessageBox.question(
            self, 
            "确认", 
            "确定要清除所有区域吗？", 
            QMessageBox.Yes | QMessageBox.No, 
            QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 清除所有区域
            self.region_mgr.clear_regions()
            
            # 更新画布
            self.canvas.draw_regions(self.region_mgr.get_all_regions(), self.region_mgr.current_index)
            
            self.statusBar().showMessage("已清除所有区域")
    
    def select_suggested_region(self):
        """选择当前建议的剪切区域"""
        if not self.canvas.current_rect:
            return
            
        # 获取当前建议的区域
        rect = self.canvas.current_rect
        
        # 弹出名称输入对话框
        dialog = RegionSettingsDialog((rect[0], rect[1], rect[2], rect[3], f"区域{len(self.region_mgr.get_all_regions())+1}"), self)
        
        if dialog.exec_():
            settings = dialog.get_settings()
            
            if settings:
                # 添加区域
                index = self.region_mgr.add_region(
                    settings["x"], settings["y"], 
                    settings["width"], settings["height"], 
                    settings["name"]
                )
                
                # 更新画布
                self.canvas.draw_regions(self.region_mgr.get_all_regions(), self.region_mgr.current_index)
                
                self.statusBar().showMessage(f"已添加区域: {settings['name']}")
    
    def on_region_adjusted(self, index, rect):
        """处理区域调整事件
        
        参数:
            index (int): 区域索引
            rect (tuple): 调整后的区域 (x, y, w, h)
        """
        # 更新区域列表中的区域数据
        region = self.region_mgr.get_region(index)
        
        # 更新列表项文本
        item_text = f"区域 {index+1}: ({rect[0]}, {rect[1]}, {rect[2]}x{rect[3]})"
        self.statusBar().showMessage(f"区域 {index+1} 已调整为: {rect}")
    
    def on_region_double_clicked(self, index):
        """处理区域双击事件
        
        参数:
            index (int): 区域索引
        """
        # 选中区域（如果未选中）
        if self.region_mgr.current_index != index:
            self.region_mgr.current_index = index
        
        # 切换到精细调整模式由ImageCanvas内部处理
        # 这里可以添加额外的状态更新逻辑

    def process_region(self, region_index):
        """处理指定索引的区域图像
        
        参数:
            region_index (int): 区域索引
        """
        if self.original_image is None:
            QMessageBox.warning(self, "警告", "请先加载原始图像")
            return
            
        if region_index < 0 or region_index >= self.region_mgr.get_region_count():
            QMessageBox.warning(self, "警告", "无效的区域索引")
            return
            
        # 获取区域数据
        region = self.region_mgr.get_region(region_index)
        if region is None:
            QMessageBox.warning(self, "警告", "无法获取区域数据")
            return
            
        # 确保区域数据有效且包含所需的坐标信息
        if len(region) < 5:
            QMessageBox.warning(self, "警告", "区域数据不完整")
            return
            
        # 从区域数据中解析坐标和名称 - 只获取前5个值
        x, y, w, h, name = region[:5]
        
        # 获取区域属性 - 背景移除设置
        bg_props = self.region_mgr.get_region_property(region_index, "bg_removal", {})
        bg_color = bg_props.get("color", [0, 255, 0])  # 默认绿色背景
        target_color = bg_props.get("target_color", None)  # 默认从图像左上角获取
        # 确保bg_threshold是整数
        bg_threshold = int(bg_props.get("threshold", 0))  # 默认不启用
            
        # 提取区域图像
        region_img = self.original_image[y:y+h, x:x+w].copy()
        
        # 如果没有指定目标颜色，使用图像左上角第一个像素点的颜色
        if target_color is None and region_img.size > 0:
            target_color = [int(c) for c in region_img[0, 0]]
        elif target_color is None:
            target_color = [255, 255, 255]  # 默认白色
        
        # 创建背景滤除对话框，传递正确格式的背景滤除参数
        dialog = BackgroundRemovalDialog(region_img, parent=self, bg_removal=(bg_color, target_color, bg_threshold))
        
        if dialog.exec_() == QDialog.Accepted:
            # 获取设置 - 返回值是元组 (背景颜色列表, 待滤除颜色列表, 阈值)
            bg_color, target_color, bg_threshold = dialog.get_settings()
            
            # 更新区域属性
            bg_props = {
                "enable": bg_threshold > 0,  # 阈值大于0表示启用
                "color": bg_color,
                "target_color": target_color,
                "threshold": bg_threshold
            }
            self.region_mgr.set_region_property(region_index, "bg_removal", bg_props)
            
            # 如果阈值为0，则不处理图像
            if bg_threshold <= 0:
                self.statusBar().showMessage("背景滤除已禁用", 5000)
                return
            
            # 处理图像
            processor = ImageProcessor()
            result_img = processor.remove_background(
                region_img,
                target_color,  # 使用待滤除颜色
                bg_threshold
            )
            
            # 保存处理后的图像
            save_path = QFileDialog.getSaveFileName(
                self,
                "保存处理后的图像",
                os.path.join(os.getcwd(), f"{name}.png"),
                "PNG图像 (*.png);;所有文件 (*.*)"
            )[0]
            
            if save_path:
                # 确保扩展名为.png
                if not save_path.lower().endswith('.png'):
                    save_path += '.png'
                    
                # 保存图像
                # cv2.imwrite(save_path, result_img)  # 直接保存BGRA图像
                # 使用image_processor处理中文文件名
                success = processor.save_image(result_img, save_path, "PNG")
                
                if success:
                    self.statusBar().showMessage(f"图像已保存到: {save_path}", 5000)
                else:
                    self.statusBar().showMessage("保存图像失败", 5000)

    def enable_color_picking(self, dialog):
        """启用颜色选择模式
        
        参数:
            dialog: 调用该方法的对话框实例
        """
        # 保存对话框引用，用于后续颜色选择回调
        self.color_picking_dialog = dialog
        
        # 确保画布存在
        if not hasattr(self, 'canvas'):
            print("错误: 没有找到canvas属性")
            return
            
        # 启用画布的颜色选择模式
        if hasattr(self.canvas, 'enable_color_picking'):
            self.canvas.enable_color_picking(True)
            self.statusBar().showMessage("请在图像上点击选择背景色")
        else:
            print("错误: canvas没有enable_color_picking方法")
            return
        
        # 连接颜色选择信号
        if hasattr(self.canvas, 'color_picked'):
            # 断开之前的连接（如果有）
            try:
                self.canvas.color_picked.disconnect()
            except:
                pass
            # 连接到当前方法
            self.canvas.color_picked.connect(self.on_color_picked)
        else:
            print("错误: canvas没有color_picked信号")

    def on_color_picked(self, color):
        """处理颜色选择事件
        
        参数:
            color (list): RGB颜色值
        """
        print(f"选中颜色: RGB({color[0]}, {color[1]}, {color[2]})")
        
        # 检查颜色选择对话框是否存在
        if hasattr(self, 'color_picking_dialog') and self.color_picking_dialog:
            # 更新对话框中的颜色
            if hasattr(self.color_picking_dialog, 'on_color_picked'):
                self.color_picking_dialog.on_color_picked(color)
            elif hasattr(self.color_picking_dialog, 'bg_color'):
                # 如果没有专门的处理方法，则直接设置背景色
                self.color_picking_dialog.bg_color = color
                if hasattr(self.color_picking_dialog, 'update_color_button'):
                    self.color_picking_dialog.update_color_button()
                if hasattr(self.color_picking_dialog, 'update_preview'):
                    self.color_picking_dialog.update_preview()
                    
            # 回复按钮文本
            if hasattr(self.color_picking_dialog, 'pick_color_button'):
                self.color_picking_dialog.pick_color_button.setText("从图像选择")
        
        # 禁用颜色选择模式
        if hasattr(self.canvas, 'enable_color_picking'):
            self.canvas.enable_color_picking(False)
        
        # 更新状态栏
        self.statusBar().showMessage(f"已选择颜色: RGB({color[0]}, {color[1]}, {color[2]})")
            
        # 取消缩放（如果有）
        if hasattr(self.canvas, 'reset_zoom'):
            self.canvas.reset_zoom()


def main():
    """应用程序主入口"""
    app = QApplication(sys.argv)
    window = ImageCutterApp()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main() 